package org.budo.launcher.undertow;

import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.Servlet;

import org.budo.launcher.service.config.AbstractWebXmlConfigParser;
import org.budo.launcher.service.config.FilterConf;
import org.budo.launcher.service.config.FilterMappingConf;
import org.budo.launcher.service.config.ServletConf;
import org.budo.support.lang.util.ReflectUtil;
import org.budo.xml.Xml;
import org.budo.xml.XmlObject;

import io.undertow.servlet.api.DeploymentInfo;
import io.undertow.servlet.api.ErrorPage;
import io.undertow.servlet.api.FilterInfo;
import io.undertow.servlet.api.ListenerInfo;
import io.undertow.servlet.api.ServletInfo;

/**
 * web.xml解析程序
 * 
 * @author lmw
 */
public class UndertowWebXmlConfigParser extends AbstractWebXmlConfigParser {
    private DeploymentInfo deploymentInfo;

    public UndertowWebXmlConfigParser(InputStream inputStream, DeploymentInfo deploymentInfo) {
        XmlObject webXml = Xml.parse(inputStream);
        this.setWebAppConf(webXml.getChildNodeByName("web-app"));

        this.deploymentInfo = deploymentInfo;
    }

    @Override
    public void addContextParam(String paramName, String paramValue) {
        deploymentInfo.addInitParameter(paramName, paramValue);
    }

    @Override
    public void addWelcomeFile(String welcomePage) {
        deploymentInfo.addWelcomePage(welcomePage);
    }

    @Override
    public void addListener(String listenerClass) {
        deploymentInfo.addListener(new ListenerInfo(ReflectUtil.classForName(listenerClass)));
    }

    @Override
    public void addErrorPage(String location, Integer errorCode) {
        deploymentInfo.addErrorPage(new ErrorPage(location, errorCode));
    }

    @Override
    public void addFilter(FilterConf filterConf) {
        String filterName = (String) filterConf.getFilterName();
        Class<? extends Filter> filterClass = (Class<? extends Filter>) filterConf.getFilterClass();

        FilterInfo filterInfo = new FilterInfo(filterName, filterClass);

        Map<String, String> initParamMap = (Map<String, String>) filterConf.getInitParamMap();
        for (Entry<String, String> entry : initParamMap.entrySet()) {
            filterInfo.addInitParam(entry.getKey(), entry.getValue());
        }

        deploymentInfo.addFilter(filterInfo);
    }

    @Override
    public void addServlet(ServletConf servletConf) {
        String servletName = servletConf.getServletName();
        Class<? extends Servlet> servletClass = (Class<? extends Servlet>) servletConf.getServletClass();

        ServletInfo servletInfo = new ServletInfo(servletName, servletClass);

        Map<String, String> initParamMap = servletConf.getInitParamMap();
        for (Entry<String, String> entry : initParamMap.entrySet()) {
            servletInfo.addInitParam(entry.getKey(), entry.getValue());
        }

        Integer loadOnStartup = servletConf.getLoadOnStartup();
        if (null != loadOnStartup) {
            servletInfo.setLoadOnStartup(loadOnStartup);
        }

        String[] urlPatterns = servletConf.getUrlPattern();
        for (String urlPattern : urlPatterns) {
            servletInfo.addMapping(urlPattern);
        }

        deploymentInfo.addServlet(servletInfo);
    }

    @Override
    public void addFilterUrlMapping(FilterMappingConf filterMappingConf) {
        List<String> dispatcherTypeList = filterMappingConf.getDispatcherTypeList();

        if (null == dispatcherTypeList || dispatcherTypeList.isEmpty()) {
            dispatcherTypeList = Arrays.asList(DispatcherType.REQUEST.name());
        }

        for (String urlPattern : filterMappingConf.getUrlPatternList()) {
            for (String dispatcherType : dispatcherTypeList) {
                deploymentInfo.addFilterUrlMapping(filterMappingConf.getFilterName(), urlPattern, DispatcherType.valueOf(dispatcherType));
            }
        }
    }
}